<?php

declare(strict_types=1);

namespace Imi\Db\Query\Interfaces;

use Imi\Db\Drivers\Contract\IDbConnection;
use Imi\Db\Query\QueryOption;
use Imi\Db\Query\Result\ChunkByOffsetResult;
use Imi\Db\Query\Result\ChunkResult;
use Imi\Db\Query\Result\CursorResult;

/**
 * 查询器接口.
 */
interface IQuery extends IBaseWhereCollector
{
    /**
     * 获取所有操作的记录.
     */
    public function getOption(): QueryOption;

    /**
     * 设置操作记录.
     *
     * @return static
     */
    public function setOption(QueryOption $option): self;

    /**
     * 获取数据库操作对象
     */
    public function getDb(): IDbConnection;

    /**
     * 设置表前缀
     */
    public function tablePrefix(string $prefix): self;

    /**
     * 设置表名.
     *
     * @param string      $table    表名
     * @param string|null $alias    别名
     * @param string|null $database 数据库名
     *
     * @return static
     */
    public function table(string $table, ?string $alias = null, ?string $database = null): self;

    /**
     * 设置表名，使用SQL原生语句.
     *
     * @return static
     */
    public function tableRaw(string $raw, ?string $alias = null): self;

    /**
     * 设置分区列表.
     */
    public function partition(?array $partitions = null): self;

    /**
     * 设置分区原生 SQL.
     */
    public function partitionRaw(string $partition): self;

    /**
     * 设置表名，table()的别名.
     *
     * @param string      $table    表名
     * @param string      $alias    别名
     * @param string|null $database 数据库名
     *
     * @return static
     */
    public function from(string $table, ?string $alias = null, ?string $database = null): self;

    /**
     * 设置表名，使用SQL原生语句.
     *
     * @return static
     */
    public function fromRaw(string $raw): self;

    /**
     * 设置 distinct.
     *
     * @param bool $isDistinct 是否设置distinct
     *
     * @return static
     */
    public function distinct(bool $isDistinct = true): self;

    /**
     * 指定查询字段.
     *
     * @return static
     */
    public function field(mixed ...$fields): self;

    /**
     * 指定查询字段，使用SQL原生语句.
     *
     * @return static
     */
    public function fieldRaw(string $raw, ?string $alias = null, array $binds = []): self;

    /**
     * join.
     *
     * @param string     $table      表名
     * @param string     $left       在 join b on a.id=b.id 中的 a.id
     * @param string     $operation  在 join b on a.id=b.id 中的 =
     * @param string     $right      在 join b on a.id=b.id 中的 b.id
     * @param string     $tableAlias 表别名
     * @param IBaseWhere $where      where条件
     * @param string     $type       join类型，默认inner
     *
     * @return static
     */
    public function join(string $table, string $left, string $operation, string $right, ?string $tableAlias = null, IBaseWhere $where = null, string $type = 'inner'): self;

    /**
     * join，使用SQL原生语句.
     *
     * @return static
     */
    public function joinRaw(string $raw, array $binds = []): self;

    /**
     * left join.
     *
     * @param string     $table      表名
     * @param string     $left       在 join b on a.id=b.id 中的 a.id
     * @param string     $operation  在 join b on a.id=b.id 中的 =
     * @param string     $right      在 join b on a.id=b.id 中的 b.id
     * @param string     $tableAlias 表别名
     * @param IBaseWhere $where      where条件
     *
     * @return static
     */
    public function leftJoin(string $table, string $left, string $operation, string $right, ?string $tableAlias = null, IBaseWhere $where = null): self;

    /**
     * right join.
     *
     * @param string     $table      表名
     * @param string     $left       在 join b on a.id=b.id 中的 a.id
     * @param string     $operation  在 join b on a.id=b.id 中的 =
     * @param string     $right      在 join b on a.id=b.id 中的 b.id
     * @param string     $tableAlias 表别名
     * @param IBaseWhere $where      where条件
     *
     * @return static
     */
    public function rightJoin(string $table, string $left, string $operation, string $right, ?string $tableAlias = null, IBaseWhere $where = null): self;

    /**
     * cross join.
     *
     * @param string     $table      表名
     * @param string     $left       在 join b on a.id=b.id 中的 a.id
     * @param string     $operation  在 join b on a.id=b.id 中的 =
     * @param string     $right      在 join b on a.id=b.id 中的 b.id
     * @param string     $tableAlias 表别名
     * @param IBaseWhere $where      where条件
     *
     * @return static
     */
    public function crossJoin(string $table, string $left, string $operation, string $right, ?string $tableAlias = null, IBaseWhere $where = null): self;

    /**
     * 排序.
     *
     * @return static
     */
    public function order(string $field, string $direction = 'asc'): self;

    /**
     * 排序
     * 支持的写法：
     * 1. id desc, age asc
     * 2. ['id'=>'desc', 'age'] // 缺省asc.
     *
     * @return static
     */
    public function orderRaw(string|array $raw, array $binds = []): self;

    /**
     * 设置分页
     * 传入当前页码和每页显示数量，自动计算offset和limit.
     *
     * @return static
     */
    public function page(?int $page, ?int $show): self;

    /**
     * 设置记录从第几个开始取出.
     *
     * @return static
     */
    public function offset(?int $offset): self;

    /**
     * 设置查询几条记录.
     *
     * @return static
     */
    public function limit(?int $limit): self;

    /**
     * group by.
     *
     * @return static
     */
    public function group(string ...$groups): self;

    /**
     * group by，使用SQL原生语句.
     *
     * @return static
     */
    public function groupRaw(string $raw, array $binds = []): self;

    /**
     * 设置 having 条件.
     *
     * @return static
     */
    public function having(string $fieldName, string $operation, mixed $value, string $logicalOperator = 'and'): self;

    /**
     * 设置 having 条件，用原生语句.
     *
     * @return static
     */
    public function havingRaw(string $raw, string $logicalOperator = 'and', array $binds = []): self;

    /**
     * 设置 having 条件，传入回调，回调中的条件加括号.
     *
     * @return static
     */
    public function havingBrackets(callable $callback, string $logicalOperator = 'and'): self;

    /**
     * 设置 having 条件，使用 IHaving 结构.
     *
     * @return static
     */
    public function havingStruct(IHaving $having, string $logicalOperator = 'and'): self;

    /**
     * 绑定预处理参数.
     *
     * @return static
     */
    public function bindValue(string|int $name, mixed $value, int $dataType = \PDO::PARAM_STR): self;

    /**
     * 批量绑定预处理参数.
     *
     * @return static
     */
    public function bindValues(array $values): self;

    /**
     * 获取绑定预处理参数关系.
     */
    public function getBinds(): array;

    /**
     * 构建查询语句.
     */
    public function buildSelectSql(): string;

    /**
     * 查询所有记录，返回数组.
     */
    public function select(): IResult;

    /**
     * 查询首条记录.
     *
     * @param string|null $className 实体类名，为null则数组每个成员为数组
     */
    public function find(?string $className = null): mixed;

    /**
     * 查询首条记录指定字段的值
     */
    public function value(string $field, mixed $default = null): mixed;

    /**
     * 得到某个列的数组.
     *
     * @param string|string[] $fields
     */
    public function column($fields, ?string $key = null): array;

    /**
     * 查询所有记录，返回游标迭代器.
     */
    public function cursor(): CursorResult;

    /**
     * 查询所有记录，返回分块迭代器.
     */
    public function chunkById(int $count, string $column, ?string $alias = null, string $orderBy = 'asc'): ChunkResult;

    /**
     * 查询所有记录，返回分块迭代器.
     */
    public function chunkByOffset(int $count): ChunkByOffsetResult;

    /**
     * 分页查询.
     */
    public function paginate(int $page, int $count, array $options = []): IPaginateResult;

    /**
     * 构建插入语句.
     */
    public function buildInsertSql(array|object|null $data = null): string;

    /**
     * 插入记录.
     */
    public function insert(array|object|null $data = null): IResult;

    /**
     * 构建批量插入语句.
     */
    public function buildBatchInsertSql(array|object|null $data = null): string;

    /**
     * 批量插入数据
     * 以首个成员作为字段标准.
     */
    public function batchInsert(array|object|null $data = null): IResult;

    /**
     * 构建更新语句.
     */
    public function buildUpdateSql(array|object|null $data = null): string;

    /**
     * 更新数据.
     */
    public function update(array|object|null $data = null): IResult;

    /**
     * 构建替换语句.
     */
    public function buildReplaceSql(array|object|null $data = null, array $uniqueFields = []): string;

    /**
     * 替换数据（Replace）.
     */
    public function replace(array|object|null $data = null, array $uniqueFields = []): IResult;

    /**
     * 构建删除语句.
     */
    public function buildDeleteSql(): string;

    /**
     * 删除数据.
     */
    public function delete(): IResult;

    /**
     * 执行SQL语句.
     */
    public function execute(string $sql): IResult;

    /**
     * 统计数量.
     */
    public function count(string $field = '*'): int;

    /**
     * 求和.
     *
     * @return int|float
     */
    public function sum(string $field);

    /**
     * 平均值
     *
     * @return int|float
     */
    public function avg(string $field);

    /**
     * 最大值
     *
     * @return int|float
     */
    public function max(string $field);

    /**
     * 最小值
     *
     * @return int|float
     */
    public function min(string $field);

    /**
     * 聚合函数.
     */
    public function aggregate(string $functionName, string $fieldName): mixed;

    /**
     * 设置update/insert/replace数据.
     *
     * @return static
     */
    public function setData(array $data): self;

    /**
     * 设置update/insert/replace的字段.
     *
     * @return static
     */
    public function setField(string $fieldName, mixed $value): self;

    /**
     * 设置update/insert/replace的字段，值为表达式，原样代入.
     *
     * @return static
     */
    public function setFieldExp(string $fieldName, string $exp, array $binds = []): self;

    /**
     * 设置递增字段.
     *
     * @return static
     */
    public function setFieldInc(string $fieldName, float $incValue = 1): self;

    /**
     * 设置递减字段.
     *
     * @return static
     */
    public function setFieldDec(string $fieldName, float $decValue = 1): self;

    /**
     * 获取自动起名的参数名称.
     */
    public function getAutoParamName(string $prefix = ':p'): string;

    /**
     * 加锁
     *
     * @return static
     */
    public function lock(int|string|bool|null $value): self;

    /**
     * 设置结果集类名.
     */
    public function setResultClass(string $resultClass): self;

    /**
     * 获取结果集类名.
     */
    public function getResultClass(): string;

    /**
     * 字段安全引用.
     */
    public function fieldQuote(string $name): string;

    /**
     * 把输入的关键字文本转为数组.
     */
    public function parseKeywordText(string $string): array;

    /**
     * 从数组拼装为有分隔标识符的关键字.
     */
    public function parseKeywordToText(array $keywords, ?string $alias = null, ?array $jsonKeywords = null): string;

    /**
     * 全文搜索.
     *
     * @param string|string[] $fieldNames
     */
    public function fullText($fieldNames, string $searchText, ?IFullTextOptions $options = null): self;
}
